package core

import (
	"sync"
	"time"
)

type Cron struct {
	tasks  *PriorityQueue[*Task]
	addCh  chan *Task
	stopCh chan struct{}
	wg     sync.WaitGroup
}

func NewCron() *Cron {
	return &Cron{
		tasks: NewPriorityQueue(func(a, b *Task) bool {
			return a.Next.Before(b.Next)
		}),
		addCh:  make(chan *Task),
		stopCh: make(chan struct{}),
	}
}

func (c *Cron) AddTask(t *Task) {
	c.addCh <- t
}

func (c *Cron) Start() {
	c.wg.Add(1)
	go c.run()
}

func (c *Cron) Stop() {
	close(c.stopCh)
	c.wg.Wait()
}

func (c *Cron) run() {
	defer c.wg.Done()
	for {
		var timer *time.Timer
		if task, ok := c.tasks.Peek(); ok {
			now := time.Now()
			next := task.Next
			wait := next.Sub(now)
			if wait < 0 {
				wait = 0
			}
			timer = time.NewTimer(wait)
		}
		var ch <-chan time.Time
		if timer != nil {
			ch = timer.C
		} else {
			ch = nil // nil channel 在 select 中永远不会被选中
		}
		select {
		case task := <-c.addCh:
			c.tasks.Push(task)
		case <-c.stopCh:
			if timer != nil {
				timer.Stop()
			}
			return
		case <-ch:
			if c.tasks.Size() == 0 {
				continue
			}
			task, _ := c.tasks.Pop()
			task.Run()
			c.tasks.Push(task)
		}
		if timer != nil {
			timer.Stop()
		}
	}
}

func (c *Cron) GetTasks() []*Task {
	return c.tasks.All()
}

// 删除指定id的任务，返回删除数量
func (c *Cron) RemoveTaskByID(id int64) int {
	return c.tasks.RemoveIf(func(t *Task) bool {
		return t.ID == id
	})
}
